#include "systemc.h"
#include "random.h"
#include "structs.h"
#include "channel.h"

SC_MODULE(execute)
{
//-------------in-out---------------------------------------------------------//
	sc_port< async_channel_in_if< deex > > deex_struct;
	sc_port< async_channel_out_if< exdm > > exdm_struct;
	sc_port< async_channel_out_if< sc_int<32> > > exde_rd;
	sc_port< async_channel_out_if< sc_uint<1> > > exfe_branch_decision;
//----------------------------------------------------------------------------//

//-------------Variáveis-Locais-----------------------------------------------//
	deex DeEx;
	exdm ExDm;
	sc_uint<32> addr_offset;
//----------------------------------------------------------------------------//

	void behavior()
	{
		while(true)
		{
			deex_struct->read(DeEx);

			switch(DeEx.op)
			{
				case 0x0:
					switch(DeEx.func)
					{
						case 0x20: //add
							exde_rd->write(DeEx.rs + DeEx.rt);
							break;
							
						case 0x22: //sub
							exde_rd->write(DeEx.rs - DeEx.rt);
							break;
							
						case 0x24: //and
							exde_rd->write(DeEx.rs & DeEx.rt);
							break;
							
						case 0x25: //or
							exde_rd->write(DeEx.rs | DeEx.rt);
							break;
							
						default:
							cout << "erro:execute: function inválida" << endl;
							break;
					}
					break;

				case 0x4: //beq
					if(DeEx.rs == DeEx.rt)
						exfe_branch_decision->write(1);
					else
						exfe_branch_decision->write(0);
					break;

				case 0x23: //lw
					if(DeEx.offset[15] == 1)
						addr_offset.range(31,16) = 0xFFFF;
					else
						addr_offset.range(31,16) = 0x0000;
					addr_offset(15,0) = DeEx.offset;
					ExDm.rd = DeEx.rs + addr_offset;
					ExDm.rw = 1;
					exdm_struct->write(ExDm);
					break;

				case 0x2B: //sw
					if(DeEx.offset[15] == 1)
						addr_offset.range(31,16) = 0xFFFF;
					else
						addr_offset.range(31,16) = 0x0000;
					addr_offset(15,0) = DeEx.offset;
					ExDm.rd = DeEx.rs + addr_offset;
					ExDm.rw = 0;
					exdm_struct->write(ExDm);
					break;
					
				case 0x08: //addi
					exde_rd->write(DeEx.rs + DeEx.offset);
					break;

				default:
					cout << "error:execute: invalid opcode (0x" << hex << DeEx.op << ")" << endl;
					break;
			}
		}
	}

	SC_CTOR(execute)
	{
		SC_THREAD(behavior);
	}
};